﻿' This software is licensed under Microsoft Public License (Ms-PL), which governs use of the accompanying software. 
' If you use the software, you accept this license. 

' The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, 
' guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot 
' change. To the extent permitted under your local laws, the contributors exclude the implied warranties of 
' merchantability, fitness for a particular purpose and non-infringement.

Imports System.ServiceModel
Imports System.ServiceModel.Web
Imports System.ServiceModel.Description

Namespace Rest
    ''' <summary>
    ''' A class for accessing Windows Communication Foundation (WCF) REST services on a client.
    ''' </summary>
    ''' <typeparam name="InterfaceType">Interface of the REST service to implement.</typeparam>
    ''' <remarks></remarks>
    Public Class RestClient(Of InterfaceType As Class)
        Implements IDisposable

#Region "Member Variables"
        Private _channelFactory As WebChannelFactory(Of InterfaceType)
        Private _implementation As InterfaceType
        Private _serviceUri As Uri
        Private _disposedValue As Boolean ' To detect redundant calls
#End Region

#Region "Constructor"
        ''' <summary>
        ''' Returns a new instance of the <see cref="RestClient(Of InterfaceType)">RestClient</see> class.
        ''' </summary>
        ''' <param name="serviceUri">URI of the REST service implementation.</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal serviceUri As Uri)
            _serviceUri = serviceUri
        End Sub
#End Region

#Region "Public Methods"
        ''' <summary>
        ''' Opens the client to communicate with the REST service.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Open() As InterfaceType
            _channelFactory = New WebChannelFactory(Of InterfaceType)(GetBinding, _serviceUri)
            InitializeEndPoint(_channelFactory.Endpoint, _channelFactory)
            _implementation = _channelFactory.CreateChannel()

            Return _implementation
        End Function

        ''' <summary>
        ''' Close the client.
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Close()
            If _channelFactory.State <> CommunicationState.Closed Then
                _channelFactory.Close()
            End If
        End Sub
#End Region

#Region "Properties"
        ''' <summary>
        ''' Gets the state of the current client.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property State As CommunicationState
            Get
                If _channelFactory Is Nothing Then
                    Return CommunicationState.Closed
                Else
                    Return _channelFactory.State
                End If
            End Get
        End Property

        ''' <summary>
        ''' Gets the proxy of the implementation.
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Proxy As InterfaceType
            Get
                Return _implementation
            End Get
        End Property
#End Region

#Region "Protected methods"
        ''' <summary>
        ''' Use this method to override any endpoint initialization.
        ''' </summary>
        ''' <param name="endpoint"></param>
        ''' <remarks></remarks>
        Protected Friend Overridable Sub InitializeEndPoint(ByRef endpoint As ServiceEndpoint, ByVal factory As WebChannelFactory(Of InterfaceType))
            ' default implementation includes RestErrorInspection            
            factory.Endpoint.Behaviors.Add(New RestClientBehavior())
        End Sub

        ''' <summary>
        ''' Use this method to override any binding initialization.
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Protected Friend Overridable Function GetBinding() As WebHttpBinding
            Return New WebHttpBinding
        End Function
#End Region

#Region "IDisposable Support"
        ''' <summary>
        ''' Dispose the client.
        ''' </summary>
        ''' <param name="disposing"></param>
        ''' <remarks></remarks>
        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not Me._disposedValue Then
                If disposing Then
                    ' TODO: dispose managed state (managed objects).
                    Me.Close()
                End If

                ' free objects
                _channelFactory = Nothing
                _implementation = Nothing

            End If
            Me._disposedValue = True
        End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class
End Namespace
